package com.abc.invoke.server.common;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.springframework.util.ReflectionUtils;

import com.google.common.collect.ClassToInstanceMap;
import com.google.common.collect.ImmutableClassToInstanceMap;
import com.google.common.collect.Lists;

public class MergeInterfacesProxy implements InvocationHandler{

	private ClassToInstanceMap<Object> classToInstanceMap;
	private MergeInterfacesProxy(final ClassToInstanceMap<Object> classToInstance){
		final Map<Class<?>, Object> map=new LinkedHashMap<Class<?>, Object>(classToInstance);
		classToInstanceMap=ImmutableClassToInstanceMap.copyOf(map);
	}
	
	
	public static <T> T newProxyInstance(final ClassToInstanceMap<Object> interfacesToDelegates, final Class<T> onlyHasMethodsFromInterfaces){
		final List<Class<?>> list=Lists.newArrayList(interfacesToDelegates.keySet());
		if(!interfacesToDelegates.containsKey(onlyHasMethodsFromInterfaces)){
			list.add(onlyHasMethodsFromInterfaces);
		}
		return (T)Proxy.newProxyInstance(MergeInterfacesProxy.class.getClassLoader(), list.toArray(new Class[list.size()]), new MergeInterfacesProxy(interfacesToDelegates));
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		if(ReflectionUtils.isEqualsMethod(method)){
			if(proxy==args[0]){
				return true;
			}
			return false;
		}else{
			if(ReflectionUtils.isHashCodeMethod(method)){
				return System.identityHashCode(proxy);
			}
			if(ReflectionUtils.isToStringMethod(method)){
				return "MergeInterfacesProxy for interfaces : "+this.classToInstanceMap.keySet();
			}
			try{
				return method.invoke(classToInstanceMap.get(method.getDeclaringClass()), args);
			}catch(InvocationTargetException e){
				throw e.getCause();
			}
		}
	}
}
